Skip to content

Conversation

@robfelty
Copy link

Valid YAML such as the following is not correctly parsed by the Spyc fork used in wp-cli. If you validate the following with other YAML validators such as yamllint.com, it is returned as valid Yaml.

key: {"json_key":"json_value", "json_key2": "json_value2"}

This should be represented in PHP as:

  'key' =>
  array (
    'json_key' => 'json_value',
    'json_key2' => 'json_value2',
  ),
)

However, when running through the Spyc.php implementation, the following is returned:

array (
  'key' =>
  array (
    0 => 'json_key":"json_value',
    1 => 'json_key2": "json_value2',
  ),
)

This can be tested by running one of the example scripts

cd examples
php yaml-load.php

I have added two additional tests in the spyc.yaml file to test this issue. If you run the example yaml-load.php script you will see that they are handled correctly and all of the existing examples are unchanged.

@swissspidy swissspidy requested a review from a team July 11, 2024 18:33
@swissspidy swissspidy requested a review from Copilot November 2, 2025 14:01

This comment was marked as resolved.

swissspidy and others added 5 commits November 2, 2025 16:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@swissspidy

This comment was marked as resolved.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly identifies and fixes a bug where YAML values containing JSON maps were not parsed correctly. The approach of using json_decode is appropriate. However, the implementation has a critical compatibility issue by using str_starts_with (a PHP 8+ function), and it could be made more robust and efficient. I've provided a detailed comment with a suggested code change to address these points, ensuring backward compatibility and improving the code's resilience.

Comment on lines +1067 to +1074
if ( str_starts_with( $value, '[{' ) || str_starts_with( $value, '{"' ) ) {
$decoded = json_decode( preg_replace( '/^.*?:\s*/', '', $line ), true );
if ($decoded !== null || (json_last_error() === JSON_ERROR_NONE && $decoded === null)) {
// Accept null as valid JSON value, but only if no error occurred
$value = $decoded;
}
// Otherwise, leave $value as-is (fallback to original string)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This is a good fix for handling JSON values. However, the current implementation has a few issues that should be addressed:

  1. PHP Compatibility (critical): The use of str_starts_with() was introduced in PHP 8.0. Using it will break backward compatibility for projects running on older PHP versions, which this library appears to support.
  2. Redundant Parsing (high): The code uses preg_replace('/^.*?:\s*/', '', $line) to re-extract the value from the line. This is unnecessary and less efficient, as the value has already been correctly parsed into the $value variable.
  3. Brittle JSON Detection (medium): The condition to detect a JSON string is too specific. It will fail for valid JSON with leading whitespace (e.g., { "key": "value" }) or other valid JSON structures.

I've provided a suggestion below that resolves all these points by using a more robust and backward-compatible approach.

        // The default inline parser (_toType) does not correctly handle complex JSON objects.
        // Attempt to parse as JSON first for values that look like potential JSON.
        $first_char = isset($value[0]) ? $value[0] : '';
        if ($first_char === '{' || $first_char === '[') {
          $decoded = json_decode($value, true);
          // If the value is valid JSON, use the decoded array.
          // This correctly handles valid JSON 'null' as well.
          if (json_last_error() === JSON_ERROR_NONE) {
            $value = $decoded;
          }
          // Otherwise, leave $value as a string for the legacy parser to handle.
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants